package com.kmxd.ams.app.watermark;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.*;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import com.kmxd.ams.client.archive.IArchiveWatermarkSvc;
import com.kmxd.ams.client.archive.vo.ArchiveWatermarkVO;
import com.kmxd.ams.client.system.ISysConfigSvc;
import com.kmxd.ams.client.watermark.IWatermarkSvc;
import com.kmxd.ams.client.watermark.vo.WatermarkVO;
import com.kmxd.ams.core.common.constant.ConfigConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.enums.ArchWatermarkTypeEnum;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.oss.template.OssTemplate;
import com.kmxd.ams.core.util.WatermarkUtil;
import com.yh.scofd.agent.HTTPAgent;
import com.yh.scofd.agent.wrapper.Const;
import com.yh.scofd.agent.wrapper.model.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 添加水印友虹实现
 *
 * @author nickbi
 */
@Slf4j
@Service(Constants.WATERMARK_SVC_PREFIX + "youhong")
@RequiredArgsConstructor
public class WatermarkYouHongSvcImpl implements IWatermarkSvc {

  private final IArchiveWatermarkSvc archiveWatermarkSvc;
  private final OssTemplate ossTemplate;
  private final ISysConfigSvc sysConfigSvc;

  /**
   * 获取地址
   *
   * @return
   */
  public String getUrl() {
    String archSeal = sysConfigSvc.getConfigContentByKey(ConfigConst.OSS_TRANSFER);
    if (StrUtil.isNotBlank(archSeal) && JSONUtil.isTypeJSON(archSeal)) {
      JSONObject sealSetting = JSONUtil.parseObj(archSeal);
      String transferURL = sealSetting.get("transferURL", String.class);
      return getServeUrl(transferURL);
    }
    return null;
  }

  public String getServeUrl(String url) {
    if (CharSequenceUtil.isBlank(url)) {
      throw BizTipException.instance("转换地址不正确");
    }
    String[] split = url.split(";");
    if (split.length == 1) {
      return split[0];
    }
    try {
      int urlHashIndex = HashUtil.additiveHash(String.valueOf(SystemClock.now()), split.length);
      return split[urlHashIndex];
    } catch (Exception e) {
      e.printStackTrace();
      throw BizTipException.instance("转换地址不正确");
    }
  }

  @Override
  public WatermarkVO addWatermark(Long archTypeId, File file, String waterMarkFilePath) {
    try {

      if (Objects.isNull(file)) {
        return WatermarkVO.builder().build();
      }

      ArchiveWatermarkVO watermark = archiveWatermarkSvc.getByArchTypeId(archTypeId);
      if (Objects.isNull(watermark)) {
        return WatermarkVO.builder().build();
      }

      // 目录不存在，创建目录
      if (!ossTemplate.exist(waterMarkFilePath)) {
        new File(waterMarkFilePath);
      }
      int angle = watermark.getAngle().intValue();
      if (watermark.getType().equals(ArchWatermarkTypeEnum.IMAGE.getType())) {
        // 图片信息
        String imagePath = ossTemplate.getAttachmentPath(null) + watermark.getPicPath();
        FileInputStream image = new FileInputStream(imagePath);
        // 图片类型
        String imageType = FileUtil.getSuffix(imagePath);
        // 透明度
        int alpha = watermark.getOpacity().intValue();
        // 是否平铺
        boolean tiled = false;

        ImageInfo imageInfo = new ImageInfo(imageType, image, alpha, tiled, true, true);
        // 需要添加水印的页面范围
        String pageFream = getPageFream(file);
        String[] size = pageFream.split(" ");
        int x = NumberUtil.parseInt(size[0]);
        int y = NumberUtil.parseInt(size[1]);
        int width = 100;
        int height = 100;
        x = (x - width) / 2;
        y = (y - height) / 2;
        MarkPosition mk = new MarkPosition(x, y, width, height);
        FileOutputStream outputStream = new FileOutputStream(waterMarkFilePath);
        HTTPAgent agent = new HTTPAgent(getUrl());
        agent.addImageMark(FileUtil.readBytes(file), outputStream, imageInfo, mk, Const.Target.OFD);
        agent.close();
      } else {
        HTTPAgent agent = new HTTPAgent(getUrl());
        String text =
            watermark.getType().equals(ArchWatermarkTypeEnum.TEXT.getType())
                ? watermark.getText()
                : WatermarkUtil.format(watermark.getDynamicInfo());
        List<TextWaterMarkInfo> infoList = Lists.newArrayList();

        TextInfo textInfo =
            new TextInfo(
                text,
                "宋体",
                watermark.getFontSize(),
                "#000000" + HexUtil.toHex(watermark.getOpacity().intValue()),
                watermark.getAngle().intValue(),
                Const.XAlign.Left,
                Const.YAlign.Top);

        JLabel label = new JLabel();
        label.setFont(new Font("宋体", Font.BOLD, watermark.getFontSize()));
        FontMetrics metrics;
        label.setText(text);
        metrics = label.getFontMetrics(label.getFont());
        int textH = metrics.getHeight();
        int textw = metrics.stringWidth(label.getText());
        int pageNum = agent.getPageCount(file);
        Pair pages = new Pair<>(1, pageNum);

        for (int i = 0; i <= 4; i++) {
          for (int j = 0; j <= 4; j++) {
            infoList.add(
                new TextWaterMarkInfo(
                    textInfo,
                    new MarkPosition(
                        i * getX(angle, textH, textw, watermark.getFontSize()) + 100,
                        j * getY(angle, textH, textw, watermark.getFontSize()) + 100,
                        getWidth(angle, textH, textw, watermark.getFontSize()),
                        getHeight(angle, textH, textw, watermark.getFontSize()),
                        pages)));
          }
        }

        FileOutputStream outputStream = new FileOutputStream(waterMarkFilePath);
        agent.addTextMarkMultiLine(file, outputStream, infoList);
        IoUtil.close(outputStream);
      }

      return WatermarkVO.builder()
          .file(ossTemplate.getFile(waterMarkFilePath))
          .path(waterMarkFilePath)
          .build();
    } catch (Exception e) {
      log.error(e.getMessage(), e);
      return WatermarkVO.builder().build();
    }
  }

  private Integer getWidth(Integer angle, Integer textH, int textW, Integer fontSize) {
    switch (angle) {
      case 0:
        return textW * fontSize;
      case 90:
        return textH;
      case 180:
        return textW * fontSize;
      case 270:
        return textH;
      case 360:
        return textW * fontSize;
      default:
        // 计算公式 cos(angle)*文字长度
        return (int) (Math.cos(angle) * textW * fontSize);
    }
  }

  private Integer getHeight(Integer angle, Integer textH, int textW, Integer fontSize) {
    switch (angle) {
      case 0:
        return textH;
      case 90:
        return textW * fontSize;
      case 180:
        return textH;
      case 270:
        return textW * fontSize;
      case 360:
        return textH;
      default:
        // 计算公式 sin(angle)*文字长度
        if (90 < angle && angle < 180) {
          return (int) (Math.cos(angle) * textW * fontSize);
        }
        return (int) (Math.sin(angle) * textW * fontSize);
    }
  }

  private Integer getX(Integer angle, Integer textH, int textW, Integer fontSize) {
    switch (angle) {
      case 0:
        return textW;
      case 90:
        return 20;
      case 180:
        return textW;
      case 270:
        return 20;
      case 360:
        return textW;
      default:
        if (angle < 90) {
          return (int) (Math.cos(angle) * textW);
        }
        if (180 < angle && angle < 270) {
          return textW;
        }
        return 20;
    }
  }

  private Integer getY(Integer angle, Integer textH, int textW, Integer fontSize) {
    switch (angle) {
      case 0:
        return 20;
      case 90:
        return textW;
      case 180:
        return 20;
      case 270:
        return textW;
      case 360:
        return 20;
      default:
        if (180 < angle && angle < 270) {
          return (int) (Math.cos(angle) * textW);
        }
        if (270 < angle && angle < 360) {
          return textW;
        }
        return (int) (Math.sin(angle) * textW);
    }
  }

  private String getPageFream(File file) {
    try {
      HTTPAgent agent = new HTTPAgent(getUrl());
      Map<Integer, String> pageSize = agent.getFilePageSize(file, new int[1]);
      if (ObjectUtil.isEmpty(pageSize)) {
        return "200 200";
      }
      for (String size : pageSize.values()) {
        return size;
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return "200 200";
  }
}
